package org.osflash.signals;

import asunit.asserts.*;
import asunit.framework.IAsync;
import org.osflash.signals.events.GenericEvent;
import org.osflash.signals.events.IEvent;
import flash.display.Sprite;

class DeluxeSignalWithGenericEventTest {

	@:meta(Inject())
	public var async : IAsync;
	var completed : DeluxeSignal;
	var delegate : Dynamic;
	@:meta(Before())
	public function setUp() : Void {
		completed = new DeluxeSignal(this);
	}

	@:meta(After())
	public function tearDown() : Void {
		completed.removeAll();
		completed = null;
		delegate = null;
	}

	@:meta(Test())
	public function signal_length_is_0_after_creation() : Void {
		assertEquals(0, completed.numListeners);
	}

	//////
	@:meta(Test())
	public function add_listener_and_dispatch_event_should_pass_event_to_listener() : Void {
		completed.add(async.add(checkGenericEvent, 10));
		completed.dispatch(new GenericEvent());
	}

	function checkGenericEvent(e : IEvent) : Void {
		assertTrue("instance of IEvent", Std.is(e, IEvent));
		assertTrue("instance of GenericEvent", Std.is(e, GenericEvent));
		assertEquals("event.signal points to the originating Signal", this.completed, e.signal);
		assertEquals("event.target points to object containing the Signal", this, e.target);
		assertEquals("event.target is e.currentTarget because event does not bubble", e.target, e.currentTarget);
	}

	//////
	@:meta(Test())
	public function add_two_listeners_and_dispatch_should_call_both() : Void {
		completed.add(async.add(checkGenericEvent, 10));
		completed.add(async.add(checkGenericEvent, 10));
		completed.dispatch(new GenericEvent());
	}

	//////
	@:meta(Test())
	public function addOnce_and_dispatch_should_remove_listener_automatically() : Void {
		completed.addOnce(newEmptyHandler());
		completed.dispatch(new GenericEvent());
		assertEquals("there should be no listeners", 0, completed.numListeners);
	}

	//////
	@:meta(Test())
	public function add_one_listener_and_dispatch_then_listener_remove_itself_using_event_signal() : Void {
		delegate = async.add(remove_myself_from_signal, 10);
		completed.add(delegate);
		completed.dispatch(new GenericEvent());
	}

	function remove_myself_from_signal(e : IEvent) : Void {
		assertEquals("listener still in signal", 1, e.signal.numListeners);
		// Can't remove(arguments.callee) because it's wrapped with delegate created by async.add().
		e.signal.remove(delegate);
		assertEquals("listener removed from signal", 0, e.signal.numListeners);
	}

	//////
	@:meta(Test())
	public function add_listener_then_remove_then_dispatch_should_not_call_listener() : Void {
		var delegate : Dynamic = failIfCalled;
		completed.add(delegate);
		completed.remove(delegate);
		completed.dispatch(new GenericEvent());
	}

	function failIfCalled(e : IEvent) : Void {
		fail("This event handler should not have been called.");
	}

	//////
	@:meta(Test())
	public function add_2_listeners_remove_2nd_then_dispatch_should_call_1st_not_2nd_listener() : Void {
		completed.add(async.add(checkGenericEvent, 10));
		var delegate : Dynamic = failIfCalled;
		completed.add(delegate);
		completed.remove(delegate);
		completed.dispatch(new GenericEvent());
	}

	//////
	@:meta(Test())
	public function add_2_listeners_should_yield_length_of_2() : Void {
		completed.add(newEmptyHandler());
		completed.add(newEmptyHandler());
		assertEquals(2, completed.numListeners);
	}

	function newEmptyHandler() : Dynamic {
		return function(e : Dynamic) : Void {
		}
;
	}

	//////
	@:meta(Test())
	public function add_2_listeners_then_remove_1_should_yield_length_of_1() : Void {
		var firstFunc : Dynamic = newEmptyHandler();
		completed.add(firstFunc);
		completed.add(newEmptyHandler());
		completed.remove(firstFunc);
		assertEquals(1, completed.numListeners);
	}

	@:meta(Test())
	public function add_2_listeners_then_removeAll_should_yield_length_of_0() : Void {
		completed.add(newEmptyHandler());
		completed.add(newEmptyHandler());
		completed.removeAll();
		assertEquals(0, completed.numListeners);
	}

	@:meta(Test())
	public function add_same_listener_twice_should_only_add_it_once() : Void {
		var func : Dynamic = newEmptyHandler();
		completed.add(func);
		completed.add(func);
		assertEquals(1, completed.numListeners);
	}

	//////
	@:meta(Test())
	public function dispatch_object_that_isnt_an_IEvent_should_dispatch_without_error() : Void {
		completed.addOnce(checkSprite);
		// Sprite doesn't have a target property,
		// so if the signal tried to set .target,
		// an error would be thrown and this test would fail.
		completed.dispatch(new Sprite());
	}

	function checkSprite(sprite : Sprite) : Void {
		assertTrue(Std.is(sprite, Sprite));
	}

	//////
}

